#include "RapidJsonHandler.h"
#include "JsonViewDlg.h"
#include "NppJsonPlugin.h"
#include "StringHelper.h"
const char *const STR_NULL  = "null";
const char *const STR_TRUE  = "true";
const char *const STR_FALSE = "false";


bool RapidJsonHandler::Null()
{
    if (!m_NodeStack.size())
        return false;

    TreeNode *parent = m_NodeStack.top();
    InsertToTree(parent, STR_NULL, false);
    m_intNodeDepth = 0;
    return true;
}

bool RapidJsonHandler::Bool(bool b)
{
    if (!m_NodeStack.size())
        return false;

    TreeNode *parent = m_NodeStack.top();
    InsertToTree(parent, b ? STR_TRUE : STR_FALSE, false);
    return true;
}

bool RapidJsonHandler::Int(int /*i*/)
{
    return true;
}

bool RapidJsonHandler::Uint(unsigned /*i*/)
{
    return true;
}

bool RapidJsonHandler::Int64(int64_t /*i*/)
{
    return true;
}

bool RapidJsonHandler::Uint64(uint64_t /*i*/)
{
    return true;
}

bool RapidJsonHandler::Double(double /*d*/)
{
    return true;
}

bool RapidJsonHandler::RawNumber(const Ch *str, unsigned /*length*/, bool /*copy*/)
{
    if (!m_NodeStack.size())
        return false;

    TreeNode *parent = m_NodeStack.top();
    InsertToTree(parent, str, false);
    return true;
}

bool RapidJsonHandler::String(const Ch *str, unsigned /*length*/, bool /*copy*/)
{
    if (!str)
        return false;

    // handle case, when there is only a value in input
    if (m_NodeStack.empty())
    {
        m_dlg->InsertToTree(m_treeRoot, str);
        return true;
    }

    TreeNode *parent = m_NodeStack.top();
    InsertToTree(parent, str, true);

    return true;
}

const char *Key_GroupName = "groupName";
const char *Key_AddressOffset = "addressOffset";
const char *Key_BitOffset     = "bitOffset";

bool RapidJsonHandler::Key(const Ch *str, unsigned /*length*/, bool /*copy*/)
{
    m_strLastKey = str;
    if (strcmp(Key_GroupName, str) == 0)
    {
        m_peripheral_group++;
        m_register_group = -1;
    }
    if (strcmp(Key_AddressOffset, str) == 0)
    {
        m_register_group++;
        m_field_group    = -1;
    }
    if (strcmp(Key_BitOffset, str) == 0)
    {
        m_field_group++;
    }
    return true;
}

std::string depth_seprator = "  ";

std::string string_repeat(std::string s, int n)
{
    std::string repeat;

    if (n <=0) {
        return "";
    }
    for (int i = 0; i < n; i++)
        repeat += s;

    return repeat;
}

bool RapidJsonHandler::StartObject()
{
    TreeNode *parent = nullptr;
    if (m_NodeStack.empty())
    {
        parent            = new TreeNode;
        parent->node.type = JsonNodeType::OBJECT;
        parent->subRoot   = m_treeRoot;
        parent->counter   = 0;
        m_NodeStack.push(parent);
    }
    else
    {
        parent = m_NodeStack.top();
    }

    if (!m_strLastKey.empty() || parent->node.type == JsonNodeType::ARRAY)
    {
        HTREEITEM newNode = nullptr;
        if (parent->node.type != JsonNodeType::ARRAY)
        {
            std::wstring wkey                  = StringHelper::ToWstring(m_strLastKey);
            std::string  depth_seprator_curr = string_repeat(depth_seprator, m_intNodeDepth);
            std::wstring w_depth_seprator_curr = StringHelper::ToWstring(depth_seprator_curr);
            _xxDebugTrace(TEXT("SO %s%s\n"), w_depth_seprator_curr.c_str(), wkey.c_str());

            newNode = m_dlg->InsertToTree(parent->subRoot, m_strLastKey);
            m_strLastKey.clear();
        }
        else
        {
            // It is an array
            std::string arr = "[" + std::to_string(parent->counter) + "]";
            newNode         = m_dlg->InsertToTree(parent->subRoot, arr);
        }

        parent->counter++;
        TreeNode *newTreeNode  = new TreeNode;
        newTreeNode->node.type = JsonNodeType::OBJECT;
        newTreeNode->subRoot   = newNode;
        newTreeNode->counter   = 0;
        m_NodeStack.push(newTreeNode);
    }

    m_intNodeDepth++;
    return true;
}

bool RapidJsonHandler::EndObject(unsigned memberCount)
{
    if (m_bFieldValue)
    {
        m_bFieldValue = false;
        memberCount += 1;
    }
    AppendNodeCount(memberCount, false);
    m_intNodeDepth--;
    return true;
}

bool RapidJsonHandler::StartArray()
{
    TreeNode *parent = nullptr;
    if (m_NodeStack.empty())
    {
        parent            = new TreeNode;
        parent->node.type = JsonNodeType::ARRAY;
        parent->subRoot   = m_treeRoot;
        parent->counter   = 0;
        m_NodeStack.push(parent);
        return true;
    }
    else
    {
        parent = m_NodeStack.top();
    }

    std::wstring ws_key                    = StringHelper::ToWstring(m_strLastKey);
    std::string  str_depth_seprator_depth  = string_repeat(depth_seprator, m_intNodeDepth);
    std::wstring ws_depth_seprator_curr    = StringHelper::ToWstring(str_depth_seprator_depth);
    _xxDebugTrace(TEXT("SA %s%s\n"), ws_depth_seprator_curr.c_str(), ws_key.c_str());

    if (!m_strLastKey.empty() || parent->node.type == JsonNodeType::ARRAY)
    {
        HTREEITEM newNode;
        if (parent->node.type != JsonNodeType::ARRAY)
        {
            newNode = m_dlg->InsertToTree(parent->subRoot, m_strLastKey);
            m_strLastKey.clear();
        }
        else
        {
            // It is an array
            std::string arr = "[" + std::to_string(parent->counter) + "]";
            newNode         = m_dlg->InsertToTree(parent->subRoot, arr);
        }


        parent->counter++;
        TreeNode *newTreeNode  = new TreeNode;
        newTreeNode->node.type = JsonNodeType::ARRAY;
        newTreeNode->subRoot   = newNode;
        newTreeNode->counter   = 0;
        m_NodeStack.push(newTreeNode);
    }
    m_intNodeDepth++;
    return true;
}

bool RapidJsonHandler::EndArray(unsigned elementCount)
{
    AppendNodeCount(elementCount, true);
    m_intNodeDepth--;
    return true;
}

const std::string NODE_BITWIDTH = std::string("bitWidth");

void RapidJsonHandler::InsertToTree(TreeNode *node, const char *const str, bool bQuote)
{
    if (!node || !str)
        return;

    if (NODE_BITWIDTH.compare(m_strLastKey) == 0)
    {
        m_bFieldValue = true;
    }

    if (node->node.type != JsonNodeType::ARRAY)
    {
        node->node.key   = m_strLastKey;
        node->node.value = str;
        m_strLastKey.clear();
    }
    else
    {
        node->node.key   = "[" + std::to_string(node->counter) + "]";
        node->node.value = str;
        node->counter++;
        m_intNodeDepth++;
    }

    // Insert item to tree
    if (bQuote)
        m_dlg->InsertToTree(node->subRoot, node->node.key + " : \"" + node->node.value + "\"");
    else
        m_dlg->InsertToTree(node->subRoot, node->node.key + " : " + node->node.value);

    if (m_bFieldValue)
    {
        TreeNode *valueNode   = new TreeNode;
        valueNode->node.type  = JsonNodeType::OBJECT;
        valueNode->counter    = 0;
        valueNode->node.key   = "value";
        valueNode->node.value = "0";
        node->counter++;
        HTREEITEM vi =m_dlg->InsertToTree(node->subRoot, valueNode->node.key + " : " + valueNode->node.value);
        m_dlg->m_lHtreeItems.push_back({m_peripheral_group, m_register_group, m_field_group, vi});
    }
}

void RapidJsonHandler::AppendNodeCount(unsigned elementCount, bool bArray)
{
    if (!m_NodeStack.empty())
    {
        TreeNode *node = m_NodeStack.top();
        m_NodeStack.pop();

        if (node->subRoot && node->subRoot != m_treeRoot)
            m_dlg->AppendNodeCount(node->subRoot, elementCount, bArray);

        delete node;
    }
}
